/** @file    EncoderWriterPlainText.cpp
 *  @author  Alessandro Polo
 *  @version $Id: EncoderWriterPlainText.cpp 1917 2010-02-22 12:05:14Z alex $
 *  @brief
 * File containing basic implementation of wosh::persistence::EncoderWriterPlainText.
 * The header for this class can be found in EncoderWriterPlainText.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <framework/persistence/EncoderWriterPlainText.h>

 #include <core/ObjectFactory.h>
 #include <core/NEW_List.h>
 #include <core/Table.h>
 #include <core/Tree.h>


using namespace std;
namespace wosh {
 namespace persistence {

 WOSH_REGISTER_INTERFACE(wosh::persistence::EncoderWriterPlainText, "wosh::EncoderWriter", 1.01, _static_EncoderWriterPlainText )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

int evalStringSize( const wosh::ISerializable* object, int maxsize  )
 {
	if ( object == NULL ) return 0;
	if ( object->isClass(_Variant_TYPE) ) {
		const wosh::Variant* obj_data = dynamic_cast<const wosh::Variant*>( object );
		if ( obj_data == NULL ) return 0;
		if ( !obj_data->isStringEmpty() )
			return obj_data->asString().size();
		return obj_data->toString().size();
	 }
	else if ( object->isClass(_Permission_TYPE) ) {
		const wosh::Permission* obj_perm = dynamic_cast<const wosh::Permission*>( object );
		if ( obj_perm == NULL ) return 0;
		return obj_perm->toUnixStyle_size();
	 }
	else { // DEPRECATED
		string temp = object->toString();
		return temp.size();
	}
	return 0;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void EncoderWriterPlainText::render( const wosh::ISerializable* object, std::stringstream& sbuffer ) {
	if ( object == NULL ) return;
	if ( object->isClass(_Variant_TYPE) ) {
		const wosh::Variant* obj_data = object->as<Variant>();
		sbuffer << obj_data->toString();
	 }
	else if ( object->isClass(_Permission_TYPE) ) {
		const wosh::Permission* obj_perm = object->as<Permission>();
		sbuffer << obj_perm->toUnixStyle();
	 }

	else if ( object->isClass(_NEW_List_TYPE) ) {
		render( object->as<NEW_List>(), sbuffer );
	 }
	else if ( object->isClass(_Table_TYPE) ) {
		render( object->as<Table>(), sbuffer );
	 }
	else if ( object->isClass(_Tree_TYPE) ) {
		render( object->as<Tree>(), sbuffer );
	 }
	else if ( object->isClass(_TreeNode_TYPE) ) {
		render( object->as<TreeNode>(), sbuffer );
	 }
	else {
		string temp = object->toString();
		if ( temp.empty() )
			sbuffer << "?[" << object->getClassName() << "]";
		else
			sbuffer << temp;
	 }
 }

void EncoderWriterPlainText::render( const wosh::NEW_List* list, stringstream& sbuffer ) {
	if ( list == NULL ) return;
	NEW_List::ConstIterator it;
	const NEW_List::ConstIterator it_end = list->end();
	for( it=list->begin(); it!=list->end(); ++it ) {
		if ( *it == NULL ) continue;
		render( *it, sbuffer );
//		sbuffer << (*it)->toString();
		sbuffer << "\r\n";
	 } 
	sbuffer << std::flush;
 }

void EncoderWriterPlainText::render( const wosh::Table* table, stringstream& sbuffer ) {
	if ( table == NULL ) return;
	int* lenghts = new int[table->getCols()];
	int spacing = 1;
	int tot_lenght = 0;
	for(unsigned int col=0; col<table->getCols(); col++) {
		lenghts[col] = 0;
		for(unsigned int row=0; row<table->getRows(); row++) {
			const wosh::ISerializable* object = table->get(row, col);
			int csize = evalStringSize(object, 40);
			if ( csize > lenghts[col] )
				lenghts[col] = csize;
		}
		lenghts[col] += spacing;
		tot_lenght += lenghts[col];
	 }
	if ( table->hasHeaderHorizontal() ) {
		for(unsigned int col=0; col<table->getCols(); col++) {
			const wosh::ISerializable* object = table->getHeaderHorizontal(col);
			int csize = evalStringSize(object, 40);
			if ( csize > lenghts[col] )
				lenghts[col] = csize + spacing;
		 }
	 }

	if ( table->hasHeaderHorizontal() ) {
		for(unsigned int col=0; col<table->getCols(); col++) {
			sbuffer.fill(' ');
			sbuffer.width(lenghts[col]);
			const wosh::ISerializable* object = table->getHeaderHorizontal(col);
			//render(object, sbuffer);
			if ( object == NULL ) sbuffer << "[NULL]";
			else sbuffer << object->toString();
		 }
		sbuffer << "\r\n";
		sbuffer.fill('-');
		sbuffer.width(tot_lenght);
		sbuffer << "-";
		sbuffer << "\r\n";
	 }
	for(unsigned int row=0; row<table->getRows(); row++) {
		for(unsigned int col=0; col<table->getCols(); col++) {
			sbuffer.fill(' ');
			sbuffer.width(lenghts[col]);
			const wosh::ISerializable* object = table->get(row, col);
			//render(object, sbuffer);
			if ( object == NULL ) sbuffer << "[NULL]";
			else sbuffer << object->toString();
		 }
		sbuffer << "\r\n";
	 }
	sbuffer << "\r\n";
	sbuffer << std::flush;
	delete [] lenghts;
	return;
 }

void EncoderWriterPlainText::render( const wosh::Tree* tree, stringstream& sbuffer ) {
	if ( !tree->hasRoot() )
		sbuffer << "(Empty Tree)";
	else {
		render( tree->getRoot(), sbuffer, 1); // recursive
	 }
	sbuffer << "\r\n";
	sbuffer << std::flush;
 }

void EncoderWriterPlainText::render( const wosh::TreeNode* treenode, stringstream& sbuffer, int indent ) {
	if ( treenode == NULL ) {
		sbuffer << "! NULL Node" << "\r\n";
		return;
	 }
	sbuffer.fill(' ');
	sbuffer.width(indent+1);
	if ( treenode->getChildren().isEmpty() )
		sbuffer << "- ";
	else
		sbuffer << "+ ";

	const wosh::ISerializable* object = treenode->getContent();
	render( object, sbuffer );
	sbuffer << "\r\n";

	if ( treenode->getChildren().isEmpty() )
		return;

	TreeNode::ChildConstIterator it;
	const TreeNode::ChildConstIterator it_end = treenode->getChildren().end();
	for( it=treenode->getChildren().begin(); it!=it_end; ++it) {
		if ( *it == NULL ) continue;
		const TreeNode* cNode = dynamic_cast<const TreeNode*>(*it);
		render(cNode, sbuffer, indent+2);
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace persistence
}; // namespace wosh
